/**
 * 
 */
package hanto.studentdlally.delta;

import hanto.common.HantoException;
import hanto.common.HantoGame;
import hanto.studentdlally.common.Coordinate;
import hanto.studentdlally.common.HantoBoard;
import hanto.studentdlally.common.HantoPiece;
import hanto.util.HantoCoordinate;
import hanto.util.HantoPieceType;
import hanto.util.HantoPlayerColor;
import hanto.util.MoveResult;

/**
 * @author Doug
 * @version 1
 */
public class DeltaHantoGame implements HantoGame {

	private HantoPlayerColor nextPlayerColor;
	private int nextMoveNumber;
	private boolean isGameOver;
	private int numBlueSparrows, numRedSparrows, numBlueCrabs, numRedCrabs;
	private HantoPiece blueButterfly, redButterfly;
	private final HantoBoard board;
	private final int MAX_SPARROWS = 4;
	private final int MAX_CRABS = 4;

	public DeltaHantoGame(){
		nextPlayerColor = HantoPlayerColor.BLUE;
		nextMoveNumber = 1;
		isGameOver = false;
		numBlueSparrows = numRedSparrows = numBlueCrabs = numRedCrabs = 0;
		blueButterfly = redButterfly = null;
		board = new HantoBoard();
	}

	/* (non-Javadoc)
	 * @see hanto.common.HantoGame#initialize(hanto.util.HantoPlayerColor)
	 */
	@Override
	public void initialize(HantoPlayerColor firstPlayer) {
		nextPlayerColor = firstPlayer;

	}

	/* (non-Javadoc)
	 * @see hanto.common.HantoGame#makeMove(hanto.util.HantoPieceType, hanto.util.HantoCoordinate, hanto.util.HantoCoordinate)
	 */
	@Override
	public MoveResult makeMove(HantoPieceType pieceType, HantoCoordinate from,
			HantoCoordinate to) throws HantoException {
		if(isGameOver){
			throw new HantoException("Game is already over");
		}
		// Did someone surrender?
		if(pieceType == null && from == null && to == null){
			isGameOver = true;
			switch(nextPlayerColor){
			case BLUE:
				return MoveResult.RED_WINS;
			case RED:
				return MoveResult.BLUE_WINS;
			default:
				break;
			}
		}

		if(!isValidMove(pieceType, from, to)){
			throw new HantoException("Invalid move");
		}
		// If we are playing a new piece:
		if(from == null){
			// Play the piece
			board.playPiece(new HantoPiece(nextPlayerColor, pieceType, to));
			incrementPieceCount(nextPlayerColor, pieceType);
		}
		// If we are moving a piece
		else{
			board.movePiece(from, to);
		}

		switchNextPlayerColor();
		nextMoveNumber++;
		blueButterfly = board.findBlueButterfly();
		redButterfly = board.findRedButterfly();

		// Check for win/draw conditions
		if(board.isSurrounded(blueButterfly) && board.isSurrounded(redButterfly)){
			isGameOver = true;
			return MoveResult.DRAW;
		}
		else if(board.isSurrounded(blueButterfly)){
			isGameOver = true;
			return MoveResult.RED_WINS;
		}
		else if(board.isSurrounded(redButterfly)){
			isGameOver = true;
			return MoveResult.BLUE_WINS;
		}

		return MoveResult.OK;
	}

	/**
	 * Makes sure this move is valid for this version of Hanto
	 * @param pieceType type of piece
	 * @param from source coordinates
	 * @param to destination coordinates
	 * @return true if the move is valid, false otherwise
	 */
	public boolean isValidMove(HantoPieceType pieceType, HantoCoordinate from,
			HantoCoordinate to) {
		// Make sure it is a valid pieceType
		if(pieceType != HantoPieceType.BUTTERFLY && pieceType != HantoPieceType.SPARROW && pieceType != HantoPieceType.CRAB){
			return false;
		}
		// First move is a bit special
		if(nextMoveNumber == 1){
			return (pieceType == HantoPieceType.BUTTERFLY && from == null && to.getX() == 0 && to.getY() == 0);
		}
		// Make sure the butterfly is being played by turn 4
		if(nextMoveNumber == 7){
			if(blueButterfly == null && pieceType != HantoPieceType.BUTTERFLY){
				return false;
			}
		}
		if(nextMoveNumber == 8){
			if(redButterfly == null && pieceType != HantoPieceType.BUTTERFLY){
				return false;
			}
		}
		// Make sure the destination is not occupied
		if(board.getPieceByCoordinates(to) != null){
			return false;
		}

		// Make sure the source is occupied
		if(from != null && board.getPieceByCoordinates(from) == null){
			return false;
		}

		// First, handle placing new pieces
		if(from == null){
			// Make sure we aren't playing too many of one piece
			if(pieceType == HantoPieceType.BUTTERFLY){
				if(hasPlayedButterfly(nextPlayerColor)){
					return false;
				}
			}
			else if(pieceType == HantoPieceType.SPARROW){
				if(nextPlayerColor == HantoPlayerColor.BLUE && numBlueSparrows >= MAX_SPARROWS){
					return false;
				}
				else if(nextPlayerColor == HantoPlayerColor.RED && numRedSparrows >= MAX_SPARROWS){
					return false;
				}
			}
			else if(pieceType == HantoPieceType.CRAB){
				if(nextPlayerColor == HantoPlayerColor.BLUE && numBlueCrabs >= MAX_CRABS){
					return false;
				}
				else if(nextPlayerColor == HantoPlayerColor.RED && numRedCrabs >= MAX_CRABS){
					return false;
				}
			}
			// Make sure the piece would be placed adjacent to existing piece(s), unless it is not the first move
			if(!board.isAdjacentToAny(to)){
				return false;
			}
			// Make sure it would not be placed adjacent to a piece of an opponents unless
			if(nextMoveNumber > 2){
				if(nextPlayerColor == HantoPlayerColor.RED){
					if(board.isAdjacentToAny(HantoPlayerColor.BLUE, to)){
						return false;
					}
				}
				else if(board.isAdjacentToAny(HantoPlayerColor.RED, to)){
					return false;
				}
			}

		}
		// Now, handle moving pieces
		else{
			// Make sure the butterfly has been played
			if(!hasPlayedButterfly(nextPlayerColor)){
				return false;
			}
			// Make sure the piece at the from coordinates matches
			final HantoPiece hp = board.getPieceByCoordinates(from);
			if(hp.getColor() != nextPlayerColor || hp.getType() != pieceType){
				return false;
			}
			//If this is a crab or butterfly, make sure it is only moving one hex
			if(pieceType == HantoPieceType.CRAB || pieceType == HantoPieceType.BUTTERFLY){
				if(!(Coordinate.generateCoordinate(from).isAdjacent(to))){
					return false;
				}
			}
			//Test moving the piece, see if it would seperate the board
			board.movePiece(from, to);
			if(!board.isConnected()){
				board.movePiece(to, from);
				return false;
			}
			// Return the board to its original state
			board.movePiece(to, from);
		}
		return true;
	}

	/**
	 * Helper method to increment the count of played pieces
	 * @param color the color of the piece that was played
	 * @param pieceType the type of the piece that was played
	 */
	private void incrementPieceCount(HantoPlayerColor color,
			HantoPieceType pieceType) {
		if(color == HantoPlayerColor.BLUE){
			if(pieceType == HantoPieceType.SPARROW){
				numBlueSparrows++;
			}
			else if(pieceType == HantoPieceType.CRAB){
				numBlueCrabs++;
			}
		}
		else if(color == HantoPlayerColor.RED){
			if(pieceType == HantoPieceType.SPARROW){
				numRedSparrows++;
			}
			else if(pieceType == HantoPieceType.CRAB){
				numRedCrabs++;
			}
		}

	}

	/**
	 * Helper method to switch the next player color
	 */
	private void switchNextPlayerColor() {
		if(nextPlayerColor == HantoPlayerColor.BLUE){
			nextPlayerColor = HantoPlayerColor.RED;
		}
		else{
			nextPlayerColor = HantoPlayerColor.BLUE;
		}

	}

	/** Checks if a player has played their butterfly
	 * @param color Color of player to check
	 * @return true if that player has played butterfly, false otherwise
	 */
	public boolean hasPlayedButterfly(HantoPlayerColor color) {
		if(color == HantoPlayerColor.BLUE){
			return blueButterfly != null;
		}
		else{
			return redButterfly != null;
		}
	}

	/* (non-Javadoc)
	 * @see hanto.common.HantoGame#getPrintableBoard()
	 */
	@Override
	public String getPrintableBoard() {
		return board.getPrintableBoard();
	}

	/**
	 * @return the board
	 */
	public HantoBoard getBoard() {
		return board;
	}

}
